//-------------------------------------------------------------------------------
//RXTX
//home:		http://rxtx.qbang.org/wiki/index.php/Installation_for_Windows 
//API:		http://users.frii.com/jarvi/rxtx/doc/index.html
//
//Copy rxtxParallel.dll 	to c:\Program Files\Java\jdk1.6.0_01\jre\bin\
//Copy rxtxSerial.dll 		to c:\Program Files\Java\jdk1.6.0_01\jre\bin\
//Copy RXTXcomm.jar 		to c:\Program Files\Java\jdk1.6.0_01\jre\lib\ext\
//-------------------------------------------------------------------------------

import java.util.Enumeration;  
  
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;



public class ComPort{  
	private String version="2013/08/10";


	private static int BUF_SIZE=0x200;
	private static int BUF_MASK=(BUF_SIZE-1);

//	private InputStream in;
	private String[] comList;


	private static int TxHead,TxTail,RxHead,RxTail;

	private static byte[] TxBuf;
	private static byte[] RxBuf;

	private static byte RTXenable=0;//[0]:TX,[1]:RX

	byte[] newbyte;


	private static int DBG=0;

	private static DBG dbg;
//	private boolean showorfile=0;//DBG message show in console mode or save in file


	public ComPort(){
		TxHead=TxTail=RxHead=RxTail=0;
//		BUF_SIZE=size;
//		BUF_MASK=(BUF_SIZE-1);
		TxHead=TxTail=RxHead=RxTail=0;
		TxBuf=new byte[BUF_SIZE];
		RxBuf=new byte[BUF_SIZE];
//System.out.println("BUF_SIZE="+BUF_SIZE);
//System.out.println("BUF_MASK="+BUF_MASK);
	}

	public ComPort(int size){
		TxHead=TxTail=RxHead=RxTail=0;
		BUF_SIZE=size;
		BUF_MASK=(BUF_SIZE-1);
		TxHead=TxTail=RxHead=RxTail=0;

//		RxHead=RxTail=(Integer.MAX_VALUE*2-2);

		TxBuf=new byte[BUF_SIZE];
		RxBuf=new byte[BUF_SIZE];

//System.out.println("BUF_SIZE="+BUF_SIZE);
//System.out.println("BUF_MASK="+BUF_MASK);
	}
	//================================================================================
	//list comport
	//================================================================================
	public String[] getList(){   
		int i=0; 
		Enumeration ports = CommPortIdentifier.getPortIdentifiers();    
		System.out.println("=========================================");  
		//get number of com
		while(ports.hasMoreElements()){

			CommPortIdentifier cpIdentifier = (CommPortIdentifier)ports.nextElement();  
//			System.out.println(i+"\t:"+cpIdentifier.getName());  
			i++;         
		}  
 
		comList=new String[i];

		Enumeration ports1 = CommPortIdentifier.getPortIdentifiers();   

		i=0;
		//save number of com
		while(ports1.hasMoreElements()){

			CommPortIdentifier cpIdentifier1 = (CommPortIdentifier)ports1.nextElement();  
//			System.out.println(cpIdentifier1.getName());  
			comList[i++]=(String)cpIdentifier1.getName();  
//			i++;
		}
//		ListNum=i;
		return comList;
	}    
//	public int getListNum(){
//		return ListNum;
//	}
	//================================================================================
	//
	//================================================================================
	public void connect (String portName,int baudrate) throws Exception{

		CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);

		if(portIdentifier.isCurrentlyOwned()){
			System.out.println("Error:"+portName +" port is currently in use");
		}
		else{

			CommPort commPort = portIdentifier.open(this.getClass().getName(),2000);
            
			if (commPort instanceof SerialPort){
				System.out.println("== "+portName+" baudrate="+baudrate+" is open =========");  
				SerialPort serialPort = (SerialPort) commPort;
				serialPort.setSerialPortParams(baudrate,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
                
				InputStream in = serialPort.getInputStream();
				OutputStream out = serialPort.getOutputStream();
                
				RTXenable=0x03;
				(new Thread(new SerialReader(in))).start();
				(new Thread(new SerialWriter(out))).start();

			}
			else{
				System.out.println("Error: Only serial ports are handled by this example.");
			}
		}     
	}

	//================================================================================
	//DBG=0x02
	//================================================================================
	public static class SerialReader implements Runnable{
		InputStream in;
        	int i=0;
		public SerialReader ( InputStream in ){
//			System.out.println("reader");
			this.in = in;
		}
        
		public void run (){
			byte[] buffer = new byte[1024];
			int inpuSize=0,tmpinputSize=0;
			int k=0;
			try{
				while((RTXenable & 0x02)==0x02){
//System.out.println("rx trigger");
					if(RxHead!=(RxTail+BUF_SIZE)){
						if(inpuSize>0){
							tmpinputSize=inpuSize;
//System.out.printf("%2d:tmpinputSize=%d\ti=%d%n",2,tmpinputSize,i);
							k=0;
							for(int j=0;j<inpuSize;j++){
								if((RxHead)==(RxTail+BUF_SIZE))
									break;
								RxBuf[RxHead & BUF_MASK]=buffer[i+j];
if((DBG & 0x02)==0x02){	
dbg.save("\t\t2:Rx["+(RxHead & BUF_MASK)+"]="+RxBuf[RxHead & BUF_MASK]+"\tRxHead="+RxHead+"\tinputSize="+tmpinputSize);
}

								RxHead++;
								k++;
								tmpinputSize--;
							}
							i+=k;
							inpuSize=tmpinputSize;
						}
						else{
							if(( inpuSize = this.in.read(buffer)) > 0){
								tmpinputSize=inpuSize;
								i=0;
								for(i=0;i<inpuSize;i++){
									if((RxHead)==(RxTail+BUF_SIZE))
										break;
									RxBuf[RxHead & BUF_MASK]=buffer[i];
								
if((DBG & 0x02)==0x02){
dbg.save("\t\t1:Rx["+(RxHead & BUF_MASK)+"]="+RxBuf[RxHead & BUF_MASK]+"\tRxHead="+RxHead+"\tinputSize="+tmpinputSize);
}
	
									RxHead++;
									tmpinputSize--;

								}
								inpuSize=tmpinputSize;
							}
							else
								i=0;
						}	
					}
				}
			}
			catch ( IOException e ){
				e.printStackTrace();
			}            
		}
	}
	//================================================================================
	//DBG==0x01
	//================================================================================
	public static class SerialWriter implements Runnable{
		OutputStream out;
        
		public SerialWriter ( OutputStream out ){
//			System.out.println("writer");
			this.out = out;
		}
        
		public void run (){
			try{                
				while((RTXenable & 0x01)==0x01){

					if(TxHead!=TxTail){
						this.out.write(TxBuf[TxTail & BUF_MASK]);
if((DBG & 0x01)==0x01){
dbg.save("\tTx["+(TxTail & BUF_MASK)+"]="+TxBuf[TxTail & BUF_MASK]+"   TxTail="+TxTail);
}
						TxTail++;
					}
				}                
			}
			catch ( IOException e ){
				e.printStackTrace();
			}            
		}
	}

	//================================================================================
	//
	//================================================================================
/*
	public void setBufSize(int size){
		BUF_SIZE=size;
		BUF_MASK=(BUF_SIZE-1);
		TxHead=TxTail=RxHead=RxTail=0;
		TxBuf=new byte[BUF_SIZE];
		RxBuf=new byte[BUF_SIZE];
	}
*/
	//================================================================================
	//
	//================================================================================
	public byte[] setTxBuf(byte[] data,int size){
		boolean alreadyCheck=false;

		int tmpTxHead=TxHead;
		int tmpTxTail=TxTail;
		byte[] returnbyte=null;

		int tmpSize=0;
//System.out.println("      input="+data[0]);

		if(((tmpTxHead))==((tmpTxTail+BUF_SIZE) )){
			if((size-tmpSize)>0){
//System.out.println("  TxBuf full=1");
				alreadyCheck=true;
			}
		}
		if(alreadyCheck==false){
			for(int i=0;i<size;i++){
				TxBuf[tmpTxHead & BUF_MASK]=data[i];
if((DBG & 0x01)==0x01){
dbg.save("TxBuf["+(tmpTxHead & BUF_MASK)+"]="+data[i]);
}
				tmpTxHead++;
				tmpSize++;

				if(((tmpTxHead) & BUF_MASK)==((tmpTxTail+BUF_SIZE) & BUF_MASK)){
					if((size-tmpSize)>0){
						alreadyCheck=true;
					}
					break;
				}
			}
		}



		if(alreadyCheck==true){
			if((size-tmpSize)>0){
				returnbyte=new byte[size-tmpSize];
				for(int j=0;j<(size-tmpSize);j++){
					returnbyte[j]=data[tmpSize+j];
				}
			}
		}
		TxHead=tmpTxHead;

		return returnbyte;
	}

	//================================================================================
	//
	//================================================================================

	public int getRxBuf_sub(){

		int tmpRxHead,tmpRxHead_1;
		int tmpRxTail,tmpRxTail_1;

		tmpRxHead=tmpRxHead_1=RxHead;
		tmpRxTail=tmpRxTail_1=RxTail;

		int tmpSize=0;
//System.out.println("tmpRxHead  ="+tmpRxHead);
//System.out.println("tmpRxTail  ="+tmpRxTail);
	
		if(tmpRxHead_1==tmpRxTail_1){
			tmpSize=0;
//System.out.println("tmpSize_0="+tmpSize);
		}
		else if((tmpRxHead_1)==(tmpRxTail_1+BUF_SIZE)){
			tmpSize=BUF_SIZE;
//System.out.println("tmpSize_1="+tmpSize);
		}
		else{
//System.out.println("getRxBuf start 0");
			while((tmpRxHead_1 & BUF_MASK)!=(tmpRxTail_1 & BUF_MASK)){
				tmpRxTail_1++;
				tmpSize++;
			}
//System.out.println("getRxBuf start 1");
//System.out.println("tmpSize_3="+tmpSize);
		}
		

//System.out.println("RxLen="+tmpSize);

		newbyte=new byte[tmpSize];
		if(tmpSize==0){

		}
		else{
			tmpSize=0;
			for(int i=0;i<newbyte.length;i++){
				newbyte[i]=RxBuf[tmpRxTail & BUF_MASK];
if((DBG & 0x02)==0x02){
dbg.save("\t\t\tRxBuf["+(tmpRxTail & BUF_MASK)+"]="+(RxBuf[tmpRxTail & BUF_MASK]));
}
			
				tmpRxTail++;
				tmpSize++;
			}
		}
//		RxTail+=tmpSize;

		return tmpSize;

	}

	//================================================================================
	//
	//================================================================================
	public byte[] getRxBuf(){

		RxTail+=getRxBuf_sub();

		return newbyte;

	}
	//================================================================================
	//
	//================================================================================

	final int _readClrBuf_=0x01;

	public byte[] getRxBuf(int fun){
		int i=getRxBuf_sub();
//System.out.println("RxTail="+RxTail);
		if((fun&_readClrBuf_)==_readClrBuf_){
			RxTail+=i;
//System.out.println("RxTail="+RxTail);
		}

		return newbyte;
	}

	//================================================================================
	//================================================================================
	public int getDBG(){
		return DBG;
	}
	//================================================================================
	//================================================================================
	public void setDBG(int dbg){
		DBG=dbg;
	

		if(dbg!=0){
			this.dbg=new DBG("ComPort.dbg");
		}
	}

	//================================================================================
	//================================================================================
	public void setDBG(int dbg,int fun){
		DBG=dbg;
	

		if(dbg!=0){
			this.dbg=new DBG("ComPort.dbg",fun);
		}
	}
	//================================================================================
	//================================================================================
	public void reset(){
		TxHead=TxTail=RxHead=RxTail=0;
		TxHead=TxTail=RxHead=RxTail=0;
		TxBuf=new byte[BUF_SIZE];
		RxBuf=new byte[BUF_SIZE];
	}
	//================================================================================
	//================================================================================
	public String getVersion(){
		return version;
	}


}  